from aiogram import Router, types, F
from aiogram.fsm.context import FSMContext
from loguru import logger as log

from database import models
from tg_bot.filters.user_filter import IsAdmin
from tg_bot.keyboards import inline, callback_factory
from tg_bot.services.text import not_correct_input
from tg_bot.states.admin import AdminCmd, AdminConsumable

CONSUMABLE_TEXT = 'Меню расходников: '


dp = Router()
dp.message.filter(IsAdmin(is_admin=True))
dp.callback_query.filter(IsAdmin())


async def admin_consumable_message(message: types.Message, state: FSMContext) -> None:
    key = inline.ConsumablePaginator(
        dp,
        before_pagination_keyboards=[await inline.add_consumable()],
        after_pagination_keyboards=[await inline.back('admin_menu')]
    )
    await message.answer(CONSUMABLE_TEXT, reply_markup=key.as_markup())
    await state.set_state(AdminConsumable.main)


@dp.callback_query(callback_factory.AdminMenuCall.filter(
    F.item == 'consumable'
), AdminCmd.main)
@dp.callback_query(callback_factory.ActionCall.filter(F.action == 'cancel'), AdminConsumable.add_name)
@dp.callback_query(callback_factory.BackCall.filter(F.to == 'consumable_menu'), AdminConsumable.info)
async def admin_consumable_menu(call: types.CallbackQuery, state: FSMContext):
    await admin_consumable_message(call.message, state)


@dp.callback_query(callback_factory.AdminActionCall.filter(
    F.action == 'add_consumable'
), AdminConsumable.main)
async def add_consumable_call(call: types.CallbackQuery, state: FSMContext):
    text = 'Введите название расходника: '
    key = await inline.cancel()
    try:
        await call.message.edit_text(text, reply_markup=key)
    except Exception as e:
        log.warning(e)
        await call.message.answer(text, reply_markup=key)
    await state.set_state(AdminConsumable.add_name)


@dp.message(AdminConsumable.add_name)
async def add_consumable_message(message: types.Message, state: FSMContext):
    if models.Consumable.objects.filter(name=message.text).count() > 0:
        await not_correct_input(message, 'Расходник с таким названием уже существует.')
    else:
        models.Consumable.objects.create(name=message.text)
        await admin_consumable_message(message, state)


@dp.message(F.text.startswith('CONSUMABLE'), F.via_bot, AdminConsumable.main)
async def admin_consumable_choice_inline(message: types.Message, state: FSMContext):
    consumable_pk: int = int(message.text.replace('CONSUMABLE ', ''))
    consumable: models.Consumable = models.Consumable.objects.filter(pk=consumable_pk).first()
    text = consumable.get_name()
    key = await inline.consumable_settings(back_to='consumable_menu')
    await message.answer(text, reply_markup=key)
    await state.set_state(AdminConsumable.info)
    await state.update_data({'consumable': consumable})


@dp.callback_query(callback_factory.ConsumableCall.filter(), AdminConsumable.main)
async def admin_consumable_choice(call: types.CallbackQuery, state: FSMContext,
                                  callback_data: callback_factory.ConsumableCall):
    consumable: models.Consumable = models.Consumable.objects.filter(pk=callback_data.pk).first()
    text = consumable.get_name()
    key = await inline.consumable_settings(back_to='consumable_menu')
    try:
        await call.message.edit_text(text, reply_markup=key)
    except Exception as e:
        log.warning(e)
        await call.message.answer(text, reply_markup=key)
    await state.set_state(AdminConsumable.info)
    await state.update_data({'consumable': consumable})


@dp.callback_query(callback_factory.AdminActionCall.filter(), AdminConsumable.info)
async def change_consumable_call(call: types.CallbackQuery, state: FSMContext,
                                 callback_data: callback_factory.AdminActionCall):
    match callback_data.action:
        case 'change_consumable_name':
            text = 'Введите новое название: '
            await state.set_state(AdminConsumable.change_name)
        case 'change_consumable_price':
            text = 'Введите новую цену: '
            await state.set_state(AdminConsumable.change_price)
        case 'change_consumable_unit':
            text = 'Введите новую меру измерения: '
            await state.set_state(AdminConsumable.change_unit)
        case _:
            text = 'Введите общее кол-во: '
            await state.set_state(AdminConsumable.change_total)
    key = await inline.cancel()
    try:
        await call.message.edit_text(text, reply_markup=key)
    except Exception as e:
        log.warning(e)
        await call.message.answer(text, reply_markup=key)


@dp.message(AdminConsumable.change_name)
@dp.message(AdminConsumable.change_price)
@dp.message(AdminConsumable.change_unit)
@dp.message(AdminConsumable.change_total)
async def change_consumable_message(message: types.Message, state: FSMContext):
    data = await state.get_data()
    consumable: models.Consumable = data.get('consumable')
    match await state.get_state():
        case AdminConsumable.change_name:
            if models.Consumable.objects.filter(name=message.text).count() > 0:
                return not_correct_input(message, 'Расходник с таким названием уже существует.')
            else:
                consumable.name = message.text
        case AdminConsumable.change_price:
            try:
                consumable.price = float(message.text)
            except Exception as e:
                log.warning(e)
                return await not_correct_input(message, 'Введите число.')
        case AdminConsumable.change_unit:
            consumable.unit = message.text
        case AdminConsumable.change_total:
            try:
                consumable.total = float(message.text)
            except Exception as e:
                log.warning(e)
                return await not_correct_input(message, 'Введите число.')
    consumable.save()
    text = consumable.get_name()
    key = await inline.consumable_settings(back_to='consumable_menu')
    await message.answer(text, reply_markup=key)
    await state.set_state(AdminConsumable.info)


@dp.callback_query(callback_factory.ActionCall.filter(F.action == 'cancel'), AdminConsumable())
async def cancel_consumable_change(call: types.CallbackQuery, state: FSMContext):
    data = await state.get_data()
    consumable: models.Consumable = data.get('consumable')
    callback_data = callback_factory.ConsumableCall(pk=consumable.pk)
    await admin_consumable_choice(call, state, callback_data)
